#include "tetattds.h"

#include <stdio.h>

#include <driver.h>
#include <theme.h>

#include "game.h"
#include "mainmenudialog.h"
#include "leveldialog.h"
#include <textentrydialog.h>
#include "util.h"
#include "settings.h"
#include "sound.h"
#include "statusdialog.h"
#include "playfield.h"

#include "state.h"
#include "fieldgraphics.h"

// TODO: Put these prototypes someplace else
void ShowSplashScreen();
void HideSplashScreen();
void InitSettings();
void SeedRandom();

static int level = 4;
extern char name[10];
extern Settings* settings;
static FwGui::Driver* gui;

static State* highscoreState;
static State* mainMenuState;
static State* endlessLevelState;
static State* vsSelfLevelState;
static State* endlessGameState;
static State* vsSelfGameState;
static State* splashScreenState;
static State* waitForGameEndState;

static State* currentState = NULL;
static State* nextState = NULL;

class HighscoreState : public State {
public:
	virtual void Enter() {
	}
	virtual void Tick() {
		const char* name;
		int score;
	
		PrintStatus("   Endless highscores\n");
		for(int i = 0; i < NUM_HIGHSCORES; i++) {
			settings->GetHighscore(0, i, name, score);
			PrintStatus("Lv %2i  %-10.10s %5i\n", i+1, name, score);
		}
	
		PrintStatus("\n   Vs Self highscores\n");
		for(int i = 0; i < NUM_HIGHSCORES; i++) {
			settings->GetHighscore(1, i, name, score);
			PrintStatus("Lv %2i  %-10.10s %5i\n", i+1, name, score);
		}

		nextState = mainMenuState;
	}
	virtual void Exit() {
	}
};

class MainMenuState : public State {
public:
	virtual void Enter() {
		dialog = new MainMenuDialog();

		gui->SetActiveDialog(dialog);

		settings->Save();
	}
	virtual void Tick() {

		switch (dialog->selection) {
		case MMSEL_NONE:
			break;

		case MMSEL_ENDLESS:
			nextState = endlessLevelState;
			break;

		case MMSEL_VS_SELF:
			nextState = vsSelfLevelState;
			break;

		case MMSEL_HIGHSCORES:
			nextState = highscoreState;
			break;
		}
	}
	virtual void Exit() {
		// to get a random field every time
		SeedRandom();

		gui->SetActiveDialog(NULL);
		delete dialog;
		dialog = NULL;
	}
private:
	MainMenuDialog* dialog;
};

class LevelState : public State {
public:
	LevelState(State* acceptState, State* cancelState)
		: dialog(NULL), acceptState(acceptState), cancelState(cancelState) {
	}
	virtual void Enter() {
		dialog = new LevelDialog(level);
		gui->SetActiveDialog(dialog);
	}
	virtual void Tick() {
		if (dialog->level >= 0) {
			level = dialog->level;
			nextState = acceptState;
		} else if (dialog->level == -2) {
			nextState = cancelState;
		}
	}
	virtual void Exit() {
		gui->SetActiveDialog(NULL);
		delete dialog;
		dialog = NULL;
	}

private:
	LevelDialog* dialog;
	State* acceptState;
	State* cancelState;
};

class TextEntryState : public State {
public:
	TextEntryState(const char* title, State* acceptState, State* cancelState) 
		: title(title), dialog(NULL), acceptState(acceptState), cancelState(cancelState) {
	}
	virtual void Enter() {
		dialog = new FwGui::TextEntryDialog(title, "", MAX_CHAT_LENGTH);
		gui->SetActiveDialog(dialog);
	}
	virtual void Tick() {
		if (dialog->ok) {
			if(strlen(GetText()) == 0) {
				nextState = cancelState;
			} else {
				nextState = acceptState;
			}
		}
	}
	virtual void Exit() {
		gui->SetActiveDialog(NULL);
		delete dialog;
		dialog = NULL;
	}
	const char* GetText() {
		return dialog->GetText();
	}
	void SetText(const char* text) {
		dialog->SetText(text);
	}
private:
	const char* title;
	FwGui::TextEntryDialog* dialog;
	State* acceptState;
	State* cancelState;
};

class GameState : public State {
public:
	GameState(State* finishState)
		: finishState(finishState) {
	}
	virtual void Enter() {
		FieldGraphics::InitGraphics();
		gameEndTimer = GAME_END_DELAY;
	}
	virtual void Tick() {
#ifdef DEBUG		// In debug mode, you can step frames with the select button
		if(!g_game->paused || keysDown() & KEY_SELECT)
#else
		if(!g_game->paused)
#endif
			g_game->Tick();
		
		g_game->Draw();

		if(g_game->field->IsState(PFS_DEAD))
		{
			gameEndTimer--;
			if(gameEndTimer == 0)
			{
				nextState = finishState;
			}
		}
	}
	virtual void Exit() {
		gui->SetListener(NULL);
		delete g_game;
		g_game = NULL;
	}
private:
	State* finishState;
	int gameEndTimer;
};

class EndlessGameState : public GameState {
public:
	EndlessGameState()
		: GameState(mainMenuState) {
	}
	virtual void Enter() {
		GameState::Enter();
		g_game = new Game(level, false);
		g_game->Start();
		gui->SetListener(g_game);
	}
	virtual void Exit() {
		settings->UpdateHighscore(0, level, name, g_game->GetScore());
		GameState::Exit();
	}
};
	
class VsSelfGameState : public GameState {
public:
	VsSelfGameState()
		: GameState(mainMenuState) {
	}
	virtual void Enter() {
		GameState::Enter();
		g_game = new Game(level, true);
		g_game->Start();
		gui->SetListener(g_game);
	}
	virtual void Exit() {
		settings->UpdateHighscore(1, level, name, g_game->GetScore());
		GameState::Exit();
	}
};

class SplashScreenState : public State {
public:
	virtual void Enter() {
		ShowSplashScreen();

		// load music
		Sound::InitMusic();
		Sound::LoadMusic();
	}

	void Tick() {
		nextState = mainMenuState;
	}
	
	void Exit() {
		HideSplashScreen();
		
		InitSettings();
	}
};

void InitStates()
{
	/* Main game state transitions
	
	mainMenuState -> select (endlessLevelState, vsSelfLevelState, highScoreState)
	endlessLevelState -> choice (endlessGameState, mainMenuState)
	endlessGameState -> always (mainMenuState)
	vsSelfLevelState -> choice (vsSelfGameState, mainMenuState)
	vsSelfGameState -> always (mainMenuState)
	highScoreState -> always (mainMenuState)
	*/

	highscoreState = new HighscoreState;
	mainMenuState = new MainMenuState;
	endlessGameState = new EndlessGameState;
	vsSelfGameState = new VsSelfGameState;
	splashScreenState = new SplashScreenState;
	endlessLevelState = new LevelState(endlessGameState, mainMenuState);
	vsSelfLevelState = new LevelState(vsSelfGameState, mainMenuState);

	currentState = splashScreenState;
	currentState->Enter();
}

bool StateTick()
{
	currentState->Tick();

	if (nextState != NULL)
	{
		currentState->Exit();
		currentState = nextState;
		nextState = NULL;
		currentState->Enter();
#if 0
		playSound(&menuSound);
#endif
	}

	if(!gui->Tick())
		return false;
	Sound::UpdateMusic();

	return true;
}


void InitGui()
{
	gui = new FwGui::Driver();
	FwGui::backgroundImage = NULL;
	FwGui::backgroundColor = FwGui::Color(0, 127, 0);
	FwGui::selectedColor = FwGui::Color(255, 255, 255);
	FwGui::labelTextColor = FwGui::Color(0, 0, 0);
	FwGui::enabledButtonColor = FwGui::Color(0, 0, 0, 190);
	FwGui::disabledButtonColor = FwGui::Color(171, 171, 171, 190);
	FwGui::buttonTextColor = FwGui::Color(255, 255, 255);
	FwGui::enabledEditBoxColor = FwGui::Color(255, 255, 255, 190);
}
